import {ClearData, DataResult, NotModify, ValueDefine, ValueStartWatchOption} from "./types"
import {IReactionOptions} from "mobx/lib/api/autorun"
import {IWhenOptions} from "mobx/lib/api/when"
import * as mobx from 'mobx'
import _ from 'lodash'
import {IReactionDisposer} from "mobx/lib/internal";
import {applyValue} from "./utils/helper";

export class WhenRunner<R> extends ValueDefine<R> {
    private option?: IWhenOptions
    private predicate: () => boolean
    private effect: () => DataResult<R>

    /**
     * 构建一个观察者定义
     */
    constructor(scope: any, predicate: () => boolean, effect: () => DataResult<R>, opts?: IWhenOptions) {
        super()
        this.predicate = predicate
        this.effect = effect
        this.option = opts
    }

    /**
     * 开启监听
     */
    start(executeOption: ValueStartWatchOption): void {

    }

    /**
     * 立刻执行
     */
    get(): DataResult<R> {
        return new Promise<R>(resolve => {
        })
    }

    /**
     * 清理观察者
     */
    dispose() {
    }
}

export class Watcher<T, R> extends ValueDefine<R> {
    private option?: IReactionOptions
    readonly watchFunc: () => T
    readonly scope: any
    thenFunc?: (args: T) => DataResult<R>
    disposeHandle?: IReactionDisposer

    /**
     * 构建一个观察者定义
     */
    constructor(scope: any, watchFunc: () => T, opts?: IReactionOptions) {
        super()
        this.scope = scope
        this.watchFunc = watchFunc
        this.option = opts
    }

    $then(thenFunc: (args: T) => DataResult<R>): Watcher<T, R> {
        this.thenFunc = thenFunc
        return this
    }

    $option(option: IReactionOptions): Watcher<T, R> {
        this.option = option
        return this
    }

    /**
     * 开启监听
     */
    start(executeOption: ValueStartWatchOption): void {
        this.disposeHandle = mobx.reaction(
            this.watchFunc,
            (result: any) => {
                if (this.thenFunc) {
                    result = this.thenFunc.call(executeOption.scope, result)
                }
                applyValue(result).then(result => {
                    if (result !== NotModify) {
                        if (executeOption.propertyName.endsWith('.value')) {
                            // value 属性是设置到 state 的, 也可以根据 bind 属性强制改变
                            const vjsonParentPath = executeOption.propertyName.substring(0, executeOption.propertyName.lastIndexOf('.'))
                            const bind = _.get(executeOption.scope.vjson, vjsonParentPath + '.bind')
                            if (bind) {
                                _.set(executeOption.scope, bind, result)

                            } else {
                                const targetVJson = _.get(executeOption.scope.vjson, vjsonParentPath)
                                if (typeof targetVJson.$getInstance === 'function') {
                                    const ctl = targetVJson.$getInstance()
                                    ctl['value'] = result
                                } else {
                                    console.error(`can't find ${vjsonParentPath}.$getInstance function. control mabe not mount`)
                                }
                            }

                        } else {
                            _.set(executeOption.scope.vjson, executeOption.propertyName, result)
                        }
                    }
                })
            },
            this.option)
    }

    /**
     * 立刻执行
     */
    get(): Promise<R> {
        return new Promise<R>(resolve => {
            let result = this.watchFunc()
            if (this.thenFunc) {
                // @ts-ignore
                result = this.thenFunc.call(this.scope, result)
            }
            applyValue(result).then(result => {
                // @ts-ignore
                resolve(result)
            })
        })
    }

    /**
     * 清理观察者
     */
    dispose() {
        if (this.disposeHandle) {
            this.disposeHandle()
        }
    }
}